/*
 * @Author: xiaosihan
 * @Date: 2021-03-28 22:21:17
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2021-11-24 02:45:13
 */

import * as THREE from "three";
import Object3D from "../Object3D/Object3D";

const originAdd = THREE.Object3D.prototype.add;

const originRemove = THREE.Object3D.prototype.remove;

const vector3Temp = new THREE.Vector3();

const quaternionTemp = new THREE.Quaternion();

export default function Object3D_mixin() {

    Object.assign(THREE.Object3D.prototype, {

        // 鼠标滑动事件
        onMousemove: undefined,

        // 鼠标离开事件
        onMouseleave: undefined,

        //鼠标进入事件
        onMouseenter: undefined,

        //鼠标按下事件
        onMousedown: undefined,

        //鼠标弹起事件
        onMouseup: undefined,

        // 点击事件
        onClick: undefined,

        //鼠标样式
        cursor: undefined,

        matrixWorldNeedsUpdate: false,

        matrixAutoUpdate: false,

        clipping: true,

        clipPlanes: [] as Array<THREE.Plane>, // 裁剪面数组

        add(...object: Object3D[]) {

            let anyThis = (this as unknown as Object3D);

            object.map(obj => {
                anyThis.clipPlanes!.map(plane => {
                    if (obj.addClipPlane) {
                        obj.addClipPlane(plane);
                    }
                });
            });

            originAdd.apply(this, object);
        },

        remove(...object: Object3D[]) {

            let anyThis = (this as unknown as Object3D);

            object.map(obj => {
                anyThis.clipPlanes!.map(plane => {
                    if (obj.removeClipPlane) {
                        obj.removeClipPlane(plane);
                    }
                });
            });

            originRemove.apply(this, object);
        },
        // 添加裁剪面
        addClipPlane(plane: THREE.Plane) {

            let anyThis = (this as unknown as Object3D);

            if (!anyThis.clipping) {
                return;
            }

            if (!anyThis.hasOwnProperty("clipPlanes")) {
                anyThis.clipPlanes = [];
            }

            if (!anyThis.clipPlanes!.includes(plane)) {
                anyThis.clipPlanes!.push(plane);
            }

            anyThis.children.map(obj => {
                if (obj.addClipPlane) {
                    obj.addClipPlane(plane);
                }
            });
        },

        // 移除裁剪面
        removeClipPlane(plane: THREE.Plane) {

            let anyThis = (this as unknown as Object3D);

            let index = anyThis.clipPlanes!.indexOf(plane);

            if (index > -1) {
                anyThis.clipPlanes!.splice(index, 1);
            }

            anyThis.children.map(obj => {
                if (obj.removeClipPlane) {
                    obj.removeClipPlane(plane);
                }
            });
        },

        // 获取世界坐标
        getWorldPosition(target: THREE.Vector3): THREE.Vector3 {

            let anyThis = (this as unknown as Object3D);

            if (target === undefined) {
                console.warn("THREE.Object3D.getWorldPosition 需要传入一个3维向量并为其赋值 避免创建新的向量");
                target = new THREE.Vector3();
            }
            // this.updateMatrixWorld(true); // 去掉更新本地矩阵计算
            return target.setFromMatrixPosition(anyThis.matrixWorld);
        },

        // 获取世界四元素
        getWorldQuaternion(target: THREE.Quaternion): THREE.Quaternion {
            let anyThis = (this as unknown as Object3D);

            if (target === undefined) {
                console.warn("THREE.Object3D.getWorldQuaternion 需要传入一个四元素并为其赋值 避免创建新的四元素");
                target = new THREE.Quaternion();
            }
            // this.updateMatrixWorld(true); // 去掉更新本地矩阵计算
            anyThis.matrixWorld.decompose(vector3Temp, target, vector3Temp);

            return target;
        },

        // 获取世界缩放
        getWorldScale(target: THREE.Vector3): THREE.Vector3 {

            let anyThis = (this as unknown as Object3D);

            if (target === undefined) {
                console.warn("THREE.Object3D.getWorldScale 需要传入一个3维向量并为其赋值 避免创建新的向量");
                target = new THREE.Vector3();
            }
            // this.updateMatrixWorld(true); // 去掉更新本地矩阵计算
            anyThis.matrixWorld.decompose(vector3Temp, quaternionTemp, target);
            return target;
        },

        // 获取世界方向向量
        getWorldDirection(target: THREE.Vector3): THREE.Vector3 {

            let anyThis = (this as unknown as Object3D);

            if (target === undefined) {
                console.warn("THREE.Object3D.getWorldDirection 需要传入一个3维向量并为其赋值 避免创建新的向量");
                target = new THREE.Vector3();
            }
            // this.updateMatrixWorld(true); // 去掉更新本地矩阵计算
            var e = anyThis.matrixWorld.elements;
            return target.set(e[8], e[9], e[10]).normalize();
        }
    });

}